{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a8b892c8",
   "metadata": {},
   "source": [
    "Printed and electronic copies of *Modeling and Simulation in Python* are available from [No Starch Press](https://nostarch.com/modeling-and-simulation-python) and [Bookshop.org](https://bookshop.org/p/books/modeling-and-simulation-in-python-allen-b-downey/17836697?ean=9781718502161) and [Amazon](https://amzn.to/3y9UxNb)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "external-reward",
   "metadata": {},
   "source": [
    "# Projecting Population Growth"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "imported-table",
   "metadata": {
    "tags": []
   },
   "source": [
    "*Modeling and Simulation in Python*\n",
    "\n",
    "Copyright 2021 Allen Downey\n",
    "\n",
    "License: [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "electoral-turkey",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# install Pint if necessary\n",
    "\n",
    "try:\n",
    "    import pint\n",
    "except ImportError:\n",
    "    !pip install pint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "formal-context",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# download modsim.py if necessary\n",
    "\n",
    "from os.path import basename, exists\n",
    "\n",
    "def download(url):\n",
    "    filename = basename(url)\n",
    "    if not exists(filename):\n",
    "        from urllib.request import urlretrieve\n",
    "        local, _ = urlretrieve(url, filename)\n",
    "        print('Downloaded ' + local)\n",
    "    \n",
    "download('https://github.com/AllenDowney/ModSimPy/raw/master/' +\n",
    "         'modsim.py')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "progressive-typing",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# import functions from modsim\n",
    "\n",
    "from modsim import *"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "global-international",
   "metadata": {
    "tags": []
   },
   "source": [
    "Here's the data from the previous chapters, one last time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "necessary-factor",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "download('https://raw.githubusercontent.com/AllenDowney/' +\n",
    "         'ModSimPy/master/data/World_population_estimates.html')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "changed-desktop",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pandas import read_html\n",
    "\n",
    "filename = 'World_population_estimates.html'\n",
    "tables = read_html(filename, header=0, index_col=0, decimal='M')\n",
    "table2 = tables[2]\n",
    "table2.columns = ['census', 'prb', 'un', 'maddison', \n",
    "                  'hyde', 'tanton', 'biraben', 'mj', \n",
    "                  'thomlinson', 'durand', 'clark']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "metallic-inventory",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "un = table2.un / 1e9\n",
    "census = table2.census / 1e9"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "current-canberra",
   "metadata": {
    "tags": []
   },
   "source": [
    "And here are the functions from the previous chapter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "measured-arthur",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "download('https://github.com/AllenDowney/ModSimPy/raw/master/' +\n",
    "         'chap06.py')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cutting-financing",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from chap06 import run_simulation\n",
    "\n",
    "def plot_estimates():\n",
    "    census.plot(style=':', label='US Census')\n",
    "    un.plot(style='--', label='UN DESA')\n",
    "    decorate(xlabel='Year', \n",
    "             ylabel='World population (billions)') "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "chicken-emphasis",
   "metadata": {},
   "source": [
    "In the previous chapter we developed a quadratic model of world\n",
    "population growth from 1950 to 2016. It is a simple model, but it fits\n",
    "the data well and the mechanisms it's based on are plausible.\n",
    "\n",
    "In this chapter we'll use the quadratic model to generate projections of future growth, and compare our results to projections from actual\n",
    "demographers."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "further-armstrong",
   "metadata": {},
   "source": [
    "## Generating Projections"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "concrete-lightning",
   "metadata": {},
   "source": [
    "Let's run the quadratic model, extending the results until 2100, and see how our projections compare to the professionals'.\n",
    "\n",
    "Here's the quadratic growth function again."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "indirect-russia",
   "metadata": {},
   "outputs": [],
   "source": [
    "def growth_func_quad(t, pop, system):\n",
    "    return system.alpha * pop + system.beta * pop**2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "little-struggle",
   "metadata": {},
   "source": [
    "And here are the system parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "comfortable-compression",
   "metadata": {},
   "outputs": [],
   "source": [
    "t_0 = census.index[0]\n",
    "p_0 = census[t_0]\n",
    "\n",
    "system = System(t_0 = t_0,\n",
    "                p_0 = p_0,\n",
    "                alpha = 25 / 1000,\n",
    "                beta = -1.8 / 1000,\n",
    "                t_end = 2100)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "legitimate-guess",
   "metadata": {},
   "source": [
    "With `t_end=2100`, we can generate the projection by calling `run_simulation` the usual way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "broken-windsor",
   "metadata": {},
   "outputs": [],
   "source": [
    "results = run_simulation(system, growth_func_quad)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "provincial-competition",
   "metadata": {},
   "source": [
    "Here are the last few values in the results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "latest-function",
   "metadata": {},
   "outputs": [],
   "source": [
    "show(results.tail())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "outer-ensemble",
   "metadata": {},
   "source": [
    "Here's what the results look like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "portable-pottery",
   "metadata": {},
   "outputs": [],
   "source": [
    "results.plot(color='gray', label='model')\n",
    "decorate(xlabel='Year', \n",
    "         ylabel='World population (billions)',\n",
    "         title='Quadratic model projection')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "macro-carroll",
   "metadata": {},
   "source": [
    "According to the model, population growth will slow gradually after 2020, approaching 12.6 billion by 2100.\n",
    "\n",
    "I am using the word *projection* deliberately, rather than\n",
    "*prediction*, with the following distinction: \"prediction\" implies\n",
    "something like \"this is what we expect to happen, at\n",
    "least approximately\"; \"projection\" implies something like \"if this\n",
    "model is a good description of the system, and if nothing in the future causes the system parameters to change, this is what would happen.\"\n",
    "\n",
    "Using \"projection\" leaves open the possibility that there are important things in the real world that are not captured in the model. It also suggests that, even if the model is good, the parameters we estimate based on the past might be different in the future.\n",
    "\n",
    "The quadratic model we've been working with is based on the assumption\n",
    "that population growth is limited by the availability of resources; in\n",
    "that scenario, as the population approaches carrying capacity, birth\n",
    "rates fall and death rates rise because resources become scarce.\n",
    "\n",
    "If that assumption is valid, we might be able to use actual population\n",
    "growth to estimate carrying capacity, provided we observe the\n",
    "transition into the population range where the growth rate starts to fall.\n",
    "\n",
    "But in the case of world population growth, those conditions don't\n",
    "apply. Over the last 50 years, the net growth rate has leveled off, but not yet started to fall, so we don't have enough data to make a credible estimate of carrying capacity. And resource limitations are probably *not* the primary reason growth has slowed. As evidence, consider:\n",
    "\n",
    "-   First, the death rate is not increasing; rather, it has declined\n",
    "    from 1.9% in 1950 to 0.8% now (see <http://modsimpy.com/mortality>).\n",
    "    So the decrease in net growth is due entirely to declining birth\n",
    "    rates.\n",
    "\n",
    "-   Second, the relationship between resources and birth rate is the\n",
    "    opposite of what the model assumes; as nations develop and people\n",
    "    become more wealthy, birth rates tend to fall.\n",
    "\n",
    "We should not take too seriously the idea that this model can estimate\n",
    "carrying capacity. But the predictions of a model can be credible even\n",
    "if the assumptions of the model are not strictly true. For example,\n",
    "population growth might behave *as if* it is resource limited, even if\n",
    "the actual mechanism is something else.\n",
    "\n",
    "In fact, demographers who study population growth often use models\n",
    "similar to ours. In the next section, we'll compare our projections to\n",
    "theirs."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "small-seminar",
   "metadata": {},
   "source": [
    "## Comparing Projections\n",
    "\n",
    "From the same Wikipedia page where we got the past population estimates, we'll read `table3`, which contains projections for population growth over the next 50-100 years, generated by the U.S. Census, U.N. DESA, and the Population Reference Bureau."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "20e6f166",
   "metadata": {},
   "outputs": [],
   "source": [
    "table3 = tables[3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "coated-smoke",
   "metadata": {},
   "source": [
    "The column names are long strings; for convenience, I'll replace them with abbreviations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "headed-tuner",
   "metadata": {},
   "outputs": [],
   "source": [
    "table3.columns = ['census', 'prb', 'un']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2a91ffb",
   "metadata": {},
   "source": [
    "Here are the first few rows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "precious-contribution",
   "metadata": {},
   "outputs": [],
   "source": [
    "table3.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f62861c1",
   "metadata": {},
   "source": [
    "Some values are `NaN`, which indicates missing data, because some organizations did not publish projections for some years.\n",
    "The following function plots projections from the U.N. DESA and U.S. Census.  It uses `dropna` to remove the `NaN` values from each series before plotting it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "paperback-delay",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_projections(table):\n",
    "    \"\"\"Plot world population projections.\n",
    "    \n",
    "    table: DataFrame with columns 'un' and 'census'\n",
    "    \"\"\"\n",
    "    census_proj = table.census.dropna() / 1e9\n",
    "    un_proj = table.un.dropna() / 1e9\n",
    "    \n",
    "    census_proj.plot(style=':', label='US Census')\n",
    "    un_proj.plot(style='--', label='UN DESA')\n",
    "    \n",
    "    decorate(xlabel='Year', \n",
    "             ylabel='World population (billions)')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "prostate-matrix",
   "metadata": {},
   "source": [
    "Here are the professional projections compared to the results of the quadratic model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "billion-dynamics",
   "metadata": {},
   "outputs": [],
   "source": [
    "results.plot(color='gray', label='model')\n",
    "plot_projections(table3)\n",
    "decorate(title='Quadratic model projection, with UN and Census')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "integrated-there",
   "metadata": {},
   "source": [
    "The U.N. DESA expects the world population to reach 11 billion around 2100, and then level off.\n",
    "Projections by U.S. Census are a little lower, and they only go until 2050.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "serial-binary",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "In this chapter we use the quadratic growth model to project world population growth between now and 2100.\n",
    "\n",
    "Real demographers expect world population to grow more slowly than our model, probably because their models are broken down by region and country, where conditions are different, and they take into account expected economic development.\n",
    "\n",
    "Nevertheless, their projections are qualitatively similar to ours, and\n",
    "theirs differ from each other almost as much as they differ from ours.\n",
    "So the results from the model, simple as it is, are not entirely unreasonable.\n",
    "\n",
    "If you are interested in some of the factors that go into the professional projections, you might like this video by Hans Rosling about the demographic changes we expect this century: <https://www.youtube.com/watch?v=ezVk1ahRF78>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "automated-simpson",
   "metadata": {},
   "source": [
    "## Exercises\n",
    "\n",
    "This chapter is available as a Jupyter notebook where you can read the text, run the code, and work on the exercises. \n",
    "You can access the notebooks at <https://allendowney.github.io/ModSimPy/>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "authorized-suggestion",
   "metadata": {},
   "source": [
    "### Exercise 1\n",
    "\n",
    " The net growth rate of world population has been declining for several decades.  That observation suggests one more way to generate more realistic projections, by extrapolating observed changes in growth rate.\n",
    "\n",
    "To compute past growth rates, we'll use a function called `diff`, which computes the difference between successive elements in a `Series`.  For example, here are the changes from one year to the next in `census`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "handmade-funeral",
   "metadata": {},
   "outputs": [],
   "source": [
    "diff = census.diff()\n",
    "show(diff.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "discrete-scanner",
   "metadata": {},
   "source": [
    "The first element is `NaN` because we don't have the data for 1949, so we can't compute the first difference.\n",
    "\n",
    "If we divide these differences by the populations, the result is an estimate of the growth rate during each year: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "objective-accused",
   "metadata": {},
   "outputs": [],
   "source": [
    "alpha = census.diff() / census\n",
    "show(alpha.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "weighted-trouble",
   "metadata": {},
   "source": [
    "The following function computes and plots the growth rates for the `census` and `un` estimates:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "unique-matrix",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_alpha():\n",
    "    alpha_census = census.diff() / census\n",
    "    alpha_census.plot(style='.', label='US Census')\n",
    "\n",
    "    alpha_un = un.diff() / un\n",
    "    alpha_un.plot(style='.', label='UN DESA')\n",
    "\n",
    "    decorate(xlabel='Year', ylabel='Net growth rate')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "flexible-amateur",
   "metadata": {},
   "source": [
    "It uses `style='.'` to plot each data point with a small circle.\n",
    "And here's what it looks like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "pressing-proceeding",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_alpha()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cross-reducing",
   "metadata": {},
   "source": [
    "Other than a bump around 1990, the net growth rate has been declining roughly linearly since 1970.\n",
    "\n",
    "We can model the decline by fitting a line to this data and extrapolating into the future.\n",
    "Here's a function that takes a time stamp and computes a line that roughly fits the growth rates since 1970."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "mexican-denver",
   "metadata": {},
   "outputs": [],
   "source": [
    "def alpha_func(t):\n",
    "    intercept = 0.02\n",
    "    slope = -0.00021\n",
    "    return intercept + slope * (t - 1970)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "handy-dubai",
   "metadata": {},
   "source": [
    "To see what it looks like, I'll create an array of time stamps from 1960 to 2020 and use `alpha_func` to compute the corresponding growth rates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "addressed-worker",
   "metadata": {},
   "outputs": [],
   "source": [
    "t_array = linspace(1960, 2020, 5)\n",
    "alpha_array = alpha_func(t_array)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "jewish-operations",
   "metadata": {},
   "source": [
    "Here's what it looks like, compared to the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "cathedral-shakespeare",
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib.pyplot import plot\n",
    "\n",
    "plot_alpha()\n",
    "plot(t_array, alpha_array, label='model', color='gray')\n",
    "\n",
    "decorate(ylabel='Net growth rate',\n",
    "         title='Linear model of net growth rate')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "expensive-viewer",
   "metadata": {},
   "source": [
    "If you don't like the `slope` and `intercept` I chose, feel free to adjust them.\n",
    "\n",
    "Now, as an exercise, you can use this function to project world population until 2100.\n",
    "\n",
    "1. Create a `System` object that includes `alpha_func` as a system parameter.\n",
    "\n",
    "2. Define a growth function that uses `alpha_func` to compute the net growth rate at the given time `t`.\n",
    "\n",
    "3. Run a simulation from 1960 to 2100 with your growth function, and plot the results.\n",
    "\n",
    "4. Compare your projections with those from the US Census and UN."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "common-april",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "ignored-chain",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "color-accountability",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "numeric-raise",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "included-vehicle",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "brown-rating",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "laughing-cylinder",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "personalized-parking",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "simple-version",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
